package com.caishi.lkx.exam.api;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.caishi.lkx.common.AdminBaseApi;
import com.caishi.lkx.common.ienum.ClientType;
import com.caishi.lkx.common.role.Roles;
import com.caishi.lkx.common.util.ConvertUtil;
import com.caishi.lkx.exam.QuestionCollectionBlockItem;
import com.caishi.lkx.exam.model.CategoryModel;
import com.caishi.lkx.exam.model.ChapterModel;
import com.caishi.lkx.exam.model.ColumnModel;
import com.caishi.lkx.exam.service.*;
import com.caishi.lkx.exam.util.WordToHtmlInOrder;
import com.caishi.lkx.exam.vo.SpecialConditionVo;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.impl.BaseIntEntity;

import com.caishi.lkx.exam.ienum.type.ColumnType;

import com.zzw.common.exception.BizException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author by Janisa
 * @Description:
 * @date 2022/2/21 16:10
 */
@Tag(name = "章节相关")
@Slf4j
@RestController
@RequestMapping("/exam/chapter")
public class ChapterApi extends AdminBaseApi<IChapterService, ChapterModel, String> {
    @Resource
    private IChapterService service;
    @Autowired
    private WordToHtmlInOrder wordToHtmlInOrder;
    @Resource
    private ICategoryService categoryService;
    @Resource
    private IExColumnConfigReService exColumnConfigReService;

    @Resource
    private IColumnService columnService;
    @Resource
    private IQuestionService questionService;

    @Resource
    private IPaperService paperService;

    @Override
    public IChapterService loadService() {
        return service;
    }

    @GetMapping("/detail/{id}")
    @Roles
    @Override
    public ChapterModel detail(@PathVariable String id) {
        return super.detail(id);
    }

    @Override
    @PutMapping("/update")
    @Transactional
    public ChapterModel update(@RequestBody ChapterModel entity) {
        ChapterModel model = service.getById(entity.getId());
        if (model.getParentId() != null && entity.getParentId() != null && !model.getParentId().equals(entity.getParentId())) {
            ChapterModel parent = service.getById(entity.getParentId());
            String oPath = parent.getOPath();
            if (StrUtil.isBlank(oPath)) {
                oPath = entity.getParentId();
            }
            entity.setPath(oPath);
            List<ChapterModel> all = new ArrayList<>();
            this.allChilderUpdatePath(entity.getId(), entity.getOPath(), all);
            for (ChapterModel chapterModel : all) {
                service.update(chapterModel);
            }
        }
        return loadService().simpleUpdate(entity);
    }

    @PutMapping("/updateWithFile")
    @Transactional
    public ChapterModel updateWithFile(@RequestPart MultipartFile file,@RequestParam(name = "params") String params ) throws IOException {

        JSONObject jsonObject = JSONUtil.parseObj(params);
        String columnId =(String) jsonObject.get("columnId");
        Long categoryId = Long.valueOf((Integer) jsonObject.get("categoryId"));


        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("columnId",columnId);
        paramsMap.put("categoryId",categoryId);
        paramsMap.put("knowledgeLevel", jsonObject.get("knowledgeLevel"));

        Map<String, Object> stringObjectMap = wordToHtmlInOrder.uploadFileToQuestion(file, paramsMap);

        ChapterModel entity=new ChapterModel();
        entity.setName((String) jsonObject.get("name"));
        entity.setServerName((String) jsonObject.get("serverName"));
        entity.setParentId((String) jsonObject.get("parentId"));
        entity.setPath((String) jsonObject.get("path"));
//        一般是true
        entity.setLeaf((Boolean) jsonObject.get("leaf"));
        entity.setCategoryId(categoryId);
        entity.setSort((Integer) jsonObject.get("sort"));

        entity.setFree( jsonObject.get("free").equals(null)?false:(Boolean) jsonObject.get("free"));
        entity.setId((String) jsonObject.get("id"));


        entity.setContent((List<QuestionCollectionBlockItem>) stringObjectMap.get("contentList"));
        entity.setQuestionIds((List<String>) stringObjectMap.get("questionIds"));
        entity.setQcount(((List<String>) stringObjectMap.get("questionIds")).size());





        ChapterModel model = service.getById(entity.getId());
//        如果parentId改变
        if (model.getParentId() != null && entity.getParentId() != null && !model.getParentId().equals(entity.getParentId())) {
            ChapterModel parent = service.getById(entity.getParentId());
//            oPath是parentId
            String oPath = parent.getOPath();
            if (StrUtil.isBlank(oPath)) {
                oPath = entity.getParentId();
            }
            entity.setPath(oPath);
            List<ChapterModel> all = new ArrayList<>();
//            扁平化获取最上传parent的所有子孙后代章节
            this.allChilderUpdatePath(entity.getId(), entity.getOPath(), all);
            for (ChapterModel chapterModel : all) {
                service.update(chapterModel);
            }
        }
        return loadService().simpleUpdate(entity);
    }

    @PutMapping("/change-qcount")
    public Integer changeQcount(@RequestBody ChapterModel chapterModel) {
        loadService().update(null, Wrappers.<ChapterModel>update()
                .setSql("qcount=" + chapterModel.getQcount())
                .eq("id", chapterModel.getId())
        );
        return chapterModel.getQcount();
    }
    @Override
    @DeleteMapping("/delete")
    @Transactional
    public Boolean delete(@RequestParam String id) {
        return loadService().delete(id);
    }

    @Override
    @DeleteMapping("/deletes")
    @Transactional
    public Boolean deletes(@RequestParam List<String> ids) {
        //如果是用试卷生成的章节必须先删除
        return loadService().delete(ids);
    }

    private void allChilderUpdatePath(String id, String basePath, List<ChapterModel> all) {
        List<ChapterModel> chapterModels = service.selectNextChildren(id);
        all.addAll(chapterModels.stream().peek(f -> {
            f.setPath(basePath);
            this.allChilderUpdatePath(f.getId(), f.getOPath(), all);
        }).toList());

    }

    @GetMapping("/child-chapter")
    @Roles
    @Operation(summary = "获取子章节")
    @Parameters({@Parameter(name = "pid", description = "父级章节id", required = true),})
    public List<ChapterModel> getChapterChildList( @RequestParam String pid) {
        List<ChapterModel> list = service.selectNextChildren(pid);
        return list.stream().sorted(Comparator.comparing(ChapterModel::getSort)).peek(v -> v.setContent(null)).toList();
    }

    @GetMapping("/all-parent-ids")
    @Roles
    @Operation(summary = "获取当前章节的所有父章节id")
    public List<String> chapterPracticeAllParentIds(@RequestParam String chapterId) {
        return service.allParentIds(chapterId);
    }

    @GetMapping("/all-children-ids")
    @Roles
    @Operation(summary = "获取当前章节的所有子章节id")
    public List<String> chapterPracticeAllChildrenIds(@RequestParam String chapterId) {
        return service.allChildrenIds(chapterId);
    }

    @GetMapping("/category-top-chapter")
    @Operation(summary = "拉取科目配置的顶级章节")
    @Roles
    public List<ChapterModel> getChapterForCategory(@RequestParam Long categoryId) {
        return columnService.categoryColumn(categoryId, ColumnType.chapterPractice).stream().flatMap(columnId -> exColumnConfigReService.getChaptersByColumn(columnId).stream()).peek(v -> v.setContent(null)).toList();
    }


    @GetMapping("/chapter-by-columnId")
    @Operation(summary = "根据栏目拉取章节")
    @Roles
    @Parameters({@Parameter(name = "columnId", description = "栏目id", required = true),})
    public List<ChapterModel> getChapterForColumn(@RequestParam Long categoryId,@RequestParam String columnId) throws BizException {
        String userId = userContext.currentUserId();



        return exColumnConfigReService.getChaptersByColumn(columnId).stream().peek(v -> {
            v.setContent(null);
            if(StrUtil.isNotBlank(userId)){
                try {
                    boolean freeFlag =  columnService.currentHaveAuth(null, null, userId, categoryId, columnId, ClientType.zyksApp);
                    if(!v.getFree()){
                        v.setFree(freeFlag);
                    }
                } catch (BizException e) {
                    throw new RuntimeException(e);
                }
            }
        }).toList();
    }

    @GetMapping("/page")
    @Override
    public IPage<ChapterModel> page(@ModelAttribute Page<ChapterModel> page, @ModelAttribute ChapterModel model, @NotNull JSONObject otherParam) {
        IPage<ChapterModel> data = loadService().page(model.getCategoryId() == null ? page : loadService().pageProcessing(page), baseWrapper(model, otherParam));
        data.setRecords(listCover(data.getRecords(), otherParam));
        return data;
    }

    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/generate-chapter")
    public void specialConditionResult(@RequestParam Long categoryId, @RequestParam Long questionSourceCategoryId, @ModelAttribute("condition") SpecialConditionVo condition, @RequestParam(defaultValue = "1") Integer count, String name, String columnId, @RequestParam(required = false) List<String> ids, @RequestParam(required = false) String chapterId) {
        //过滤试题数目为null数据
        List<SpecialConditionVo.TY> collect = condition.getTypes().stream().filter(f -> null != f.getCount()).collect(Collectors.toList());
        condition.setTypes(collect);
        if (StrUtil.isBlank(columnId)) {
            ColumnModel columnModel = columnService.selectFirst(Wrappers.<ColumnModel>lambdaQuery().eq(ColumnModel::getType, ColumnType.chapterPractice).eq(ColumnModel::getCategoryId, categoryId).eq(ColumnModel::getName, "综合练习"));
            if (null == columnModel) {
                var column = new ColumnModel();
                column.setType(ColumnType.chapterPractice);
                column.setName("综合练习");
                column.setCategoryId(categoryId);
                columnService.insert(column);
                columnId = column.getId();
            } else {
                columnId = columnModel.getId();
            }
        }
        List<String> inIds = null;
        if (null != ids && !ids.isEmpty()) {
            inIds = paperService.getQuestionIdsByPaper(ids);
        }
        List<String> chapterIds = new ArrayList<>();
        for (var i = 0; i < count; i++) {
            var chapterName = count == 1 ? name : name + ConvertUtil.toChinese(String.valueOf(i + 1));
            ChapterModel model = service.categoryGenerateChapter(categoryId, questionSourceCategoryId, condition, chapterName, columnId, inIds, chapterId);
            if (null != model) {
                chapterIds.add(model.getId());
            }
        }
        if (null != ids && !ids.isEmpty()) {
            service.saveChapterPaperSet(categoryId, chapterIds, ids);
        }
    }

    @Override
    protected LambdaQueryWrapper<ChapterModel> baseWrapper(ChapterModel model, JSONObject otherParam) {
        boolean tree = otherParam.getBool("tree", false);
        return super.baseWrapper(model, otherParam).select(ChapterModel::getId, ChapterModel::getParentId, ChapterModel::getName, ChapterModel::getSort,ChapterModel::getServerName, ChapterModel::getCategoryId,ChapterModel::getQcount).eq(tree, ChapterModel::getParentId, "0");
    }

    @Override
    protected List<ChapterModel> listCover(List<ChapterModel> result, JSONObject otherParam) {
        boolean tree = otherParam.getBool("tree", false);
        boolean categoryName = otherParam.getBool("categoryName", false);
        Map<Long, String> nameMap = new HashMap<>();
        var categoryIds = result.stream().map(ChapterModel::getCategoryId).distinct().toList();
        if (categoryName && !categoryIds.isEmpty()) {
            for (var category : categoryService.selectList(categoryService.wrappers().select(CategoryModel::getName, BaseIntEntity::getId).in(categoryIds.size() > 1, BaseIntEntity::getId, categoryIds).eq(categoryIds.size() == 1, BaseIntEntity::getId, categoryIds.get(0)))) {
                nameMap.put(category.getId(), category.getName());
            }
        }
       var list =  result.parallelStream().map(c -> {
            if (categoryName) {
                c.setCategoryName(nameMap.get(c.getCategoryId()));
            }
            if (tree) {
                c = service.setChildren(c);
                service.treeProcess(c, (child, p) -> child.setCategoryName(p.getCategoryName()));
            }
            return c;
        }).toList();
        return list;
    }

}
